#include "software.h"
#include "utils.h"

#include <boost/tokenizer.hpp>
#include <boost/regex.hpp>

#if defined (RedHat)
#include "librpmcpp/rpmcpp.h"
#endif

#include <iostream>


namespace software {

#if defined (Debian)  || defined (Ubuntu)
namespace dpkg {

enum FieldIndex
{
    EN_NAME = 1,
    EN_VERSION,
    EN_ARCHITECTURE,
    EN_DESCRIPTION
};

TSoftwareList software_list()
{
    TSoftwareList software_list;

    const char *cmd = "dpkg -l";

    FILE *pipe = popen(cmd, "r");
    std::string output;
    char buffer[128];
    if (NULL == pipe)
    {
        output = std::string("popen(") + cmd +") => NULL";
        return software_list;
    }

    while(!feof(pipe))
    {
        bzero(buffer, 128);
        if (NULL != fgets(buffer, 128, pipe))
        {
            output += buffer;
        }
    }
    pclose(pipe);
    pipe = NULL;
    boost::char_separator<char> return_space("\n");
    typedef boost::tokenizer< boost::char_separator<char> > ReturnTokens;
    ReturnTokens return_tokens(output, return_space);
    std::vector<std::string> lines(return_tokens.begin(), return_tokens.end());

    boost::regex reg_ii("^(ii|rc)", boost::regex::icase);
    for (std::vector<std::string>::iterator iter = lines.begin(); iter != lines.end(); ++iter)
    {
        // 如果不是ii开头的行，则跳过
        if (!boost::regex_search(*iter, reg_ii))
        {
            continue;
        }

        // std::cout << "=> line: " << *iter << std::endl;
        SoftwarePackageInfos software;
        // 分割信息，提取软件名，版本，架构，描述
        boost::char_separator<char> sep_space(" ");
        typedef boost::tokenizer< boost::char_separator<char> > Tokens;
        Tokens tokens(*iter, sep_space);

        std::vector<std::string> fields(tokens.begin(), tokens.end());
        // 软件名称
        std::string name = fields[EN_NAME];
        std::string::size_type find_pos = name.find(":");
        if (std::string::npos != find_pos)
        {
            name = name.substr(0, find_pos);
        }
        software.m_software_name = name;

        // 版本
        std::string version = fields[EN_VERSION];
        find_pos = version.find("-");
        if (std::string::npos != find_pos)
        {
            version = version.substr(0, find_pos);
        }
        find_pos = version.find("+");
        if (std::string::npos != find_pos)
        {
            version = version.substr(0, find_pos);
        }
        find_pos = version.find("~");
        if (std::string::npos != find_pos)
        {
            version = version.substr(0, find_pos);
        }
        software.m_version = software::utils::purge_version_string(version.c_str());

        // 架构
        software.m_architecture = fields[EN_ARCHITECTURE];
        // 描述
        software.m_description = fields[EN_DESCRIPTION];

        if (software.m_software_name.empty() || software.m_version.empty())
        {
            continue;
        }

        /*
        std::cout << "=> name: " << software.m_software_name
                  << ", version: " << software.m_version
                  << ", architecture: " << software.m_architecture
                  << ", description: " << software.m_description
                  << std::endl;
        */
        software_list.push_back(software);
    }

    return software_list;
}

}

#endif

#if defined (RedHat)
namespace rpm {
TSoftwareList software_list()
{
    librpm::CRpmQuery::librpm_configured();
    librpm::CRpmQuery query;
    query.query_all();

    TSoftwareList software_list;

    const librpm::TSoftwareList &fields = query.get_results();
    for (librpm::TSoftwareList::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
    {
        const librpm::SoftwarePackageInfos software = *iter;

        software::SoftwarePackageInfos software_infos;
        software_infos.m_software_name= software.m_software_name;
        std::transform(software_infos.m_software_name.begin(), software_infos.m_software_name.end(), software_infos.m_software_name.begin(), ::tolower);

        for (librpm::TFieldContents::const_iterator iter_field = software.m_fields.begin(); iter_field != software.m_fields.end(); ++iter_field)
        {
            const librpm::FieldContent *field = *iter_field;

            if (field->name == "VERSION")
            {
                software_infos.m_version = field->content.str.ptr;
            }
            if (field->name == "DESCRIPTION")
            {
                software_infos.m_description = field->content.str.ptr;
            }
        }

        software_list.push_back(software_infos);

    }
    return software_list;
}
}
#endif

TSoftwareList software_list()
{
#if defined (RedHat)
    return software::rpm::software_list();
#else
    return software::dpkg::software_list();
#endif
}

}


